﻿package fab.geom
{
	import flash.geom.Point;
	import flash.geom.Rectangle;

	public class Segment extends Line
	{
		public var debut:Point;
		public var fin:Point;
		public var rectangle:Rectangle;

		public function Segment( d:Point, f:Point )
		{
			//debut = d;
			//fin = f;					
			debut =  new Point( int( d.x ), int( d.y ) );
			fin =  new Point( int( f.x ), int( f.y ) );
			super(debut, fin, "points");
			rectangle = new Rectangle( Math.min( debut.x, fin.x ), Math.min( debut.y, fin.y ), Math.abs( debut.x - fin.x ),  Math.abs( debut.y - fin.y ) );
		}
		override public function update( d:Point, f:Point ):void
		{
			//debut = d;
			//fin = f;		
			debut =  new Point( int( d.x ), int( d.y ) );
			fin =  new Point( int( f.x ), int( f.y ) );
			super.update( debut, fin );
			rectangle = new Rectangle( Math.min( debut.x, fin.x ), Math.min( debut.y, fin.y ), Math.abs( debut.x - fin.x ),  Math.abs( debut.y - fin.y ) );
		}		
		static public function intersection(seg1:Segment, seg2:Segment):Point
		{
			var p:Point = Line.intersection( seg1, seg2 );
			if ( p == null ) return  null;
			//if ( seg1.rectangle.containsPoint( p ) && seg2.rectangle.containsPoint( p ) ) return p;// non
			if ( seg1.containsPoint( p ) && seg2.containsPoint( p ) ) return p;		
			return null;
		}	
		public function pointAt(q:Number):Point
		{
			return Point.interpolate( fin, debut, q );
		}		
		static public function double_interpolate( dp1:Segment, dp2:Segment, f:Number ):Segment
		{
			return new Segment( Point.interpolate(dp1.debut, dp2.debut, f ), Point.interpolate(dp1.fin, dp2.fin,  f ) );
		}	
		public function oriente_x( vers_la_droite:Boolean=true ):void
		{
			if ( ( debut.x > fin.x && vers_la_droite ) || ( debut.x < fin.x && !vers_la_droite ) )
			{
				//var tmp:Point = debut.clone();
				//debut = fin.clone();
				//fin = tmp;
				update( fin.clone(), debut.clone() );
			}
		}
		public function inverse():void
		{
			update( fin.clone(), debut.clone() );
		}		
		public function get longueur():Number
		{
			return Point.distance( debut, fin );
		}	
		public function get vecteur():Point
		{
			return fin.subtract( debut );
		}		
		public function instersectRectangle(recta:Rectangle):Segment
		{
			//if ( !rect.intersects( rectangle ) ) return null;// non
			var rect:Rectangle = recta.clone();
			var contains_debut:Boolean = rect.containsPoint( debut );
			var contains_fin:Boolean = rect.containsPoint( fin );
			
			var top_side:Segment;
			var left_side:Segment;
			var bottom_side:Segment;
			var right_side:Segment;
			var top_side_point:Point;
			var left_side_point:Point;
			var bottom_side_point:Point;
			var right_side_point:Point;
			
			if ( contains_debut && contains_fin )
			{
				return clone();
			}
			else if ( contains_debut || contains_fin )// fonctionnerait avec nimporte quel quadrilatere !
			{
				var inside_point:Point = contains_debut?debut:fin;

				top_side = new Segment( rect.topLeft, rect.topLeft.add( new Point( rect.width, 0 ) ) );
				top_side_point = Segment.intersection( this, top_side );
				if ( top_side_point != null ) return new Segment( top_side_point, inside_point );
				
				left_side = new Segment( rect.topLeft, rect.topLeft.add( new Point( 0, rect.height ) ) );
				left_side_point = Segment.intersection( this, left_side );
				if ( left_side_point != null ) return new Segment( left_side_point, inside_point );
				
				bottom_side = new Segment( rect.bottomRight, rect.bottomRight.add( new Point( - rect.width, 0 ) ) );
				bottom_side_point = Segment.intersection( this, bottom_side );
				if ( bottom_side_point != null ) return new Segment( inside_point, bottom_side_point );			
				
				right_side = new Segment( rect.bottomRight, rect.bottomRight.add( new Point( 0, - rect.height ) ) );
				right_side_point = Segment.intersection( this, right_side );
				if ( right_side_point != null ) return new Segment( inside_point, right_side_point );
			}
			else {
				var two_points:Array = new Array();
				
				left_side = new Segment( rect.topLeft, rect.topLeft.add( new Point( 0, rect.height ) ) );
				left_side_point = Segment.intersection( this, left_side );
				if ( left_side_point != null ) two_points.push( left_side_point );
				//if ( two_points.length == 2 ) return new Segment( two_points[ 0 ], two_points[ 1 ] );
				
				top_side = new Segment( rect.topLeft, rect.topLeft.add( new Point( rect.width, 0 ) ) );
				top_side_point = Segment.intersection( this, top_side );
				if ( top_side_point != null ) two_points.push( top_side_point );
				if ( two_points.length == 2 ) return new Segment( two_points[ 0 ], two_points[ 1 ] );
				
				bottom_side = new Segment( rect.bottomRight, rect.bottomRight.add( new Point( - rect.width, 0 ) ) );
				bottom_side_point = Segment.intersection( this, bottom_side );
				if ( bottom_side_point != null ) two_points.push( bottom_side_point );	
				if ( two_points.length == 2 ) return new Segment( two_points[ 0 ], two_points[ 1 ] );
				
				right_side = new Segment( rect.bottomRight, rect.bottomRight.add( new Point( 0, - rect.height ) ) );
				right_side_point = Segment.intersection( this, right_side );
				if ( right_side_point != null ) two_points.push( right_side_point );
				if ( two_points.length == 2 ) return new Segment( two_points[ 0 ], two_points[ 1 ] );
			}
			return null;
		}
		public function containsPoint( p:Point ):Boolean
		{
			//isOnLine ???
			//return rectangle.left <= p.x && p.x <= rectangle.right && rectangle.top <= p.y && p.y <= rectangle.bottom;
			return rectangle.left <= Math.round( p.x ) && Math.round( p.x ) <= rectangle.right && rectangle.top <= Math.round( p.y ) && Math.round( p.y ) <= rectangle.bottom;
		}			
		public function clone():Segment
		{
			return new Segment( debut, fin );
		}	
		override public function toString():String
		{
			return "Segment " + debut + " / " + fin;
		}			
	}
}